/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fallen.deck;

import csm.uttils.Archive;
import fallen.deck.entity.Card;
import fallen.deck.entity.Deck;
import fallen.deck.front_end.MainWindow;
import fallen.deck.hibernate.Queries;
import java.awt.HeadlessException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.ObjectMapper;

/**
 *
 * @author MotorolaUTN
 */
public final class Drecker {

    public final static int INFO_MESSAGE = 0;
    public final static int WARNING_MESSAGE = 1;
    public final static int ERROR_MESSAGE = 2;
    private static MainWindow window = null;

    /**
     * @param aWindow the window to set
     */
    public static void setWindow(MainWindow aWindow) {
        window = aWindow;
    }

    public static void addDeckTab(Deck newDeck) {
        getWindow().addDeckTab(newDeck);
    }

    /**
     * @return the window
     */
    public static MainWindow getWindow() {
        return window;
    }

    public static void inform(String message) {
        inform(message, INFO_MESSAGE);
    }

    public static void inform(String message, int messageType) {
        String msgType;
        switch (messageType) {
            case WARNING_MESSAGE:
                msgType = "[WARN]";
                break;
            case ERROR_MESSAGE:
                msgType = "[ERRO]";
                break;
            default:
                try {
                    window.setStatus(message);
                } catch (NullPointerException e) {
                    System.out.println("[WARN]Main Window not ready.");
                }
                msgType = "[INFO]";
                break;
        }
        System.out.println(msgType + message);
    }

    public static void importDeck() throws IOException {
        Drecker.inform("Importing deck...");
        File file = getFileToLoad();
        if (file == null) {
            return;
        }
        Archive archive = new Archive(file.getAbsolutePath());
        Deck deck = getDeckFromJson(archive.readString());
        if (!Queries.checkName(deck.getName())) {
            String newName = JOptionPane.showInputDialog(window, "Ya existe un mazo con el nombre \""
                    + deck.getName() + "\" en la base de datos.\n¿Deseas darle un nuevo nombre al mazo a importar?", deck.getName(), WARNING_MESSAGE);
            if (newName.compareTo("") == 0) {
                Drecker.inform("Importación cancelada");
                return;
            } else {
                deck.setName(newName);
            }
        }
        Queries.save(deck);
        addDeckTab(deck);
    }

    private static Deck getDeckFromJson(String json) throws IOException {
        Deck deck = new Deck();
        JsonFactory f = new JsonFactory();
        JsonParser jp = f.createJsonParser(json);
        jp.nextToken();
        while (jp.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jp.getCurrentName();
            jp.nextToken();
            if ("deckName".equals(fieldname)) { // contains an object
                deck.setName(jp.getText());
            } else if ("demon".equals(fieldname)) {
                String expantion = "", number = "";
                while (jp.nextToken() != JsonToken.END_OBJECT) {
                    jp.nextToken(); // move to value
                    String namefield = jp.getCurrentName();
                    if ("expantion".equals(namefield)) {
                        expantion = jp.getText();
                    } else if ("number".equals(namefield)) {
                        number = jp.getText();
                    } else {
                        throw new IllegalStateException("Unrecognized field '" + fieldname + "'!");
                    }
                }
                Card demon = Queries.getCard(expantion, Integer.parseInt(number));
                deck.setDemon(demon);
            } else if ("notes".equals(fieldname)) {
                deck.setNotes(jp.getText());
            } else if ("cards".equals(fieldname)) {
                while (jp.nextToken() != JsonToken.END_ARRAY) {
                    String expantion = "", number = "", quantity = "";
                    //jp.nextToken(); // move to value
                    while (jp.nextToken() != JsonToken.END_OBJECT) {
                        jp.nextToken(); // move to value
                        String namefield = jp.getCurrentName();
                        if ("expantion".equals(namefield)) {
                            expantion = jp.getText();
                        } else if ("number".equals(namefield)) {
                            number = jp.getText();
                        } else if ("quantity".equals(namefield)) {
                            quantity = jp.getText();
                        } else {
                            throw new IllegalStateException("Unrecognized field '" + fieldname + "'!");
                        }
                    }
                    Card card = Queries.getCard(expantion, Integer.parseInt(number));
                    for (int i = 0; i < Integer.parseInt(quantity); i++) {
                        deck.getCards().add(card);
                    }
                }
            } else {
                throw new IllegalStateException("Unrecognized field '" + fieldname + "'!");
            }
        }
        jp.close(); // ensure resources get cleaned up timely and properly

        return deck;
    }

    public static void exportDeck(Deck deck) {
        try {
            Drecker.inform("Exporting deck...");
            File file = getFileToSave(deck);
            if (file == null) {
                return;
            }
            //Archive archive = new Archive(file.getAbsolutePath());
            //archive.writeString(getJsonFromDeck(deck), false);

            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(file, getJsonStructureFromDeck(deck));
            Drecker.inform(deck.getName() + " exportado satisfactoriamente.");
        } catch (IOException ex) {
            Logger.getLogger(Drecker.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private static File getFileToSave(Deck deck) throws HeadlessException {
        JFileChooser jfChooser = new JFileChooser();
        jfChooser.setFileFilter(new FileNameExtensionFilter("Decks Files", "dkr"));
        jfChooser.setSelectedFile(new File(deck.getName() + ".dkr"));
        jfChooser.showDialog(window, "Exportar");
        File file = jfChooser.getSelectedFile();
        return file;
    }

    private static File getFileToLoad() throws HeadlessException {
        JFileChooser jfChooser = new JFileChooser();
        jfChooser.setFileFilter(new FileNameExtensionFilter("Decks Files", "dkr"));
        jfChooser.showOpenDialog(window);
        //jfChooser.showDialog(window, "Importar");
        File file = jfChooser.getSelectedFile();
        return file;
    }

    private static HashMap<String, Object> getJsonStructureFromDeck(Deck deck) {

        HashMap<String, String> mDemon = new HashMap<String, String>();
        mDemon.put("expantion", deck.getDemon().getExpansion().getName());
        mDemon.put("number", String.valueOf(deck.getDemon().getNumber()));

        ArrayList cards = new ArrayList();
        Object[][] deckRows = deck.getRows();
        for (int i = 0; i < deckRows.length; i++) {
            HashMap<String, String> mCard = new HashMap<String, String>();
            Card card = (Card) deckRows[i][0];
            mCard.put("quantity", String.valueOf((Integer) deckRows[i][1]));
            mCard.put("expantion", card.getExpansion().getName());
            mCard.put("number", String.valueOf(card.getNumber()));
            cards.add(mCard);
        }

        HashMap<String, Object> mDeck = new HashMap<String, Object>();
        mDeck.put("notes", deck.getNotes());
        mDeck.put("cards", cards);
        mDeck.put("demon", mDemon);
        mDeck.put("deckName", deck.getName());

        return mDeck;
    }
}
